#include "stdafx.h"
#include <string>
using std::string;

#include <regex>
using std::regex;
using std::regex_replace;
using std::regex_match;
using std::sregex_iterator;

#include <iostream>
#include <fstream>
using std::cout;
using std::endl;
using std::ostream;
using std::ifstream;


#include <map>
using std::map;

#include <algorithm>
using std::min;
using std::max;
using std::stoi;
using std::stof;

class Config {
	map<string, map<string, string>> map;	
public:
	Config(string);
	string str;

	double GetDouble(string, double);
	int    GetInt(string, int);
	string GetString(string, string);
	bool   GetBool(string, bool);
};

ostream &operator<<(ostream &os, Config& m) {
	return os << m.str;
}

bool stob(string s) { 
	regex e("TRUE", std::regex_constants::icase); 
	return regex_match(s, e) ? true : false; 
}

double Config::GetDouble(string key, double defval = 0)   { return map[key]["DOUBLE"] == "" ? defval : stof(map[key]["DOUBLE"]); }
int    Config::GetInt   (string key, int defval = 0)      { return map[key]["INT"]    == "" ? defval : stoi(map[key]["INT"]);    }
string Config::GetString(string key, string defval = "")  { return map[key]["STRING"] == "" ? defval : map[key]["STRING"] ;      }
bool   Config::GetBool  (string key, bool defval = false) { return map[key]["BOOL"]   == "" ? defval : stob(map[key]["BOOL"]);   }

Config::Config(string path){
	ifstream t(path);
	string s((std::istreambuf_iterator<char>(t)),std::istreambuf_iterator<char>());
	t.close();

	//group 1,2,3,4,5 = property,float,int,string,bool
	regex expr("([\\w]+)\\s*=\\s*(?:(\\d+\\.+\\d+|\\.\\d+|\d+\\.)|(\\d+)|(\"[^\r\n:]*\")|(TRUE|FALSE))", std::regex_constants::icase);
	for (sregex_iterator it(s.begin(), s.end(), expr), itEnd; it != itEnd; it++)
	{
		string key, type, value; int i;
		if      ((*it)[2].matched) { i = 2; type = "DOUBLE"; }
		else if ((*it)[3].matched) { i = 3; type = "INT";    }
		else if ((*it)[4].matched) { i = 4; type = "STRING"; }
		else                       { i = 5; type = "BOOL";   }
		key   = (*it)[1].str();
		value = (*it)[i].str();
		map[key][type] = value;
		str += type + " -> " + key + " = " + value + "\n";
	}
}

int main()
{
	Config config = "H:\\Audio\\PitchDetectorv8\\elan_code\\config code\\NEW config format.txt";
	cout << config;

	//MODULES
	auto FileOutput    = config.GetBool("FileOutput");
	auto PitchDetector = config.GetBool("PitchDetector");
	auto Tuner         = config.GetBool("Tuner");
	auto HarmSplitter  = config.GetBool("HarmSplitter");
	auto PhaseLocker   = config.GetBool("PhaseLocker");

	//FILE MANAGER
	auto RenameFile_AvgFreq  = config.GetBool("RenameFile_AvgFreq");
	auto RenameFile_NoteName = config.GetBool("RenameFile_NoteName");
	auto RenameFile_Prefix   = config.GetString("RenameFile_Prefix");
	auto RenameFile_Suffix   = config.GetString("RenameFile_Suffix");
	auto OutputFolder        = config.GetString("OutputFolder");

	//PITCH DETECTOR
	auto AnalysisChannel       = min(config.GetInt("AnalysisChannel") - 1, 0);
	auto BlockSize             = config.GetInt("AnalysisChannel", 8);
	auto Overlap               = config.GetInt("AnalysisChannel", 16);
	auto NormalizeForDetection = config.GetBool("NormalizeForDetection");

	//TUNER
	auto Smoothing     = config.GetDouble("Smoothing");
	auto Envelope      = config.GetDouble("Envelope");
	auto TransientTime = config.GetDouble("TransientTime");

	//PHASE LOCKER
	auto FFTSize    = config.GetInt("FFTSize", 32768);
	auto FFTOverlap = config.GetInt("FFTOverlap", 8);
	auto WindowType = config.GetInt("WindowType");
	auto MaxFreq    = config.GetDouble("MaxFreq");

	return 0;
}